#include <stdio.h>
#include <stdlib.h>

#include "os_thread.h"

#ifdef WIN32
#include <windows.h>
#else//POSIX: linux, mac os
#include <pthread.h>
#endif

int os_thread_create(int (*thread_func)(void *param), void *thread_param, os_thread_t **thread)
{
	if (!thread) {
		return -1;
	}

	*thread = (os_thread_t *)malloc(sizeof(os_thread_t));
	memset(*thread, 0, sizeof(os_thread_t));

#ifdef WIN32
	(*thread)->thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, (LPVOID)thread_param, 0, (LPDWORD)&((*thread)->thread_pid));
	if (!(*thread)->thread_handle) {
		printf("create thread failure\n");
		return -1;
	}
#else // posix: linux, mac os
	if( pthread_create((*thread)->thread_handle,NULL,thread_func,thread_param) != 0 ){
		printf("create thread failure\n");
		return -1;
	}
#endif

	return 0;
}

int os_thread_destroy(os_thread_t *thread)
{
	return 0;
}

int os_mutex_create(os_mutex_t **mutex)
{
	if (!mutex)	{
		return -1;
	}
	os_mutex_t *pMutex = (os_mutex_t *)malloc(sizeof(os_mutex_t));
	memset(pMutex, 0, sizeof(os_mutex_t));
#ifdef WIN32
	pMutex->handle = CreateMutexA(NULL, 0, (LPCSTR)"Mutex for os_mutex_create");
	if (pMutex->handle == NULL) {
		printf("create a mutex failure\n");
		free(pMutex);
		pMutex = NULL;
		return -1;
	}
#else
	pMutex->handle = (void *)malloc(sizeof(pthread_mutex_t));
	if (pthread_mutex_init(pMutex->handle, NULL) != 0){
		printf("create a mutex failure\n");
		free(pMutex->handle);
		free(pMutex);
		return -1;
	}
#endif
	*mutex = pMutex;

	return 0;
}
int os_mutex_lock(os_mutex_t *mutex)
{
	if( !mutex || !mutex->handle ){
		return -1;
	}
#ifdef WIN32
	if( WaitForSingleObject(mutex->handle,60*1000*10)!=0 ){
		return -1;
	}
#else
	pthread_mutex_lock(mutex->handle);
#endif

	return 0;
}
int os_mutex_unlock(os_mutex_t *mutex)
{
	if( !mutex || !mutex->handle ){
		return -1;
	}
#ifdef WIN32
	ReleaseMutex(mutex->handle);
#else
	pthread_mutex_unlock(mutex->handle);
#endif

	return 0;
}
int os_mutex_destroy(os_mutex_t *mutex)
{
	if( !mutex || !mutex->handle ){
		return 0;
	}
#ifdef WIN32
	CloseHandle(mutex->handle);
#else
	pthread_mutex_destroy(mutex->handle);
#endif
	free(mutex);
	mutex = NULL;

	return 0;
}


int os_event_create(os_event_t **event)
{
	if ( !event ) {
		return -1;
	}

	os_event_t *pEvent = (os_event_t*)malloc(sizeof(os_event_t));
	if( !pEvent ){
		return -1;
	}
#ifdef WIN32
	pEvent->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
	if( !pEvent->handle ){
		pEvent->handle = NULL;
		return -1;;
	}
#else
	pEvent->cond = malloc(sizeof(pthread_cond_t));
	pEvent->mutex = malloc(sizeof(pthread_mutex_t));
	pthread_cond_init(pEvent->cond, NULL);
	pthread_mutex_init(pEvent->mutex, NULL);
#endif

	*event = pEvent;

	return 0;
}

int os_event_wait(os_event_t *event, int milliseconds)
{
	DWORD dwWait = 0;

	if( !event ){
		return -1;
	}

#ifdef WIN32
	if (!event->handle){
		return -1;
	}
	dwWait = WaitForSingleObject(event->handle, milliseconds);
	if (dwWait==WAIT_OBJECT_0){
		return 0;
	}
	else if (dwWait==WAIT_TIMEOUT){
		return -1;
	}
	else{
		return -1;
	}struct timespec;
#else
	if (!event->cond || !event->mutex){
		return -1;
	}
	struct timeval now;
	struct timespec timeout;
	gettimeofday(&now,NULL);
	int total_usec = now.tv_usec + milliseconds*1000;
	timeout.tv_sec = now.tv_sec + total_usec/1000000;
	timeout.tv_nsec = total_usec%1000000;

	pthread_mutex_lock(event->mutex);
	if (pthread_cond_timewait(event->cond, event->mutex, &timeout)==ETIMEOUT){
		pthread_mutex_unlock(event->mutex);
		return -1;
	}
	else {
		pthread_mutex_unlock(event->mutex);
		return 0;
	}

#endif
	return 0;
}

int os_event_set(os_event_t *event)
{
	if( !event ){
		return -1;
	}
#ifdef WIN32
	if( !event->handle ){
		return -1;
	}
	if( SetEvent(event->handle)==FALSE ){
		return -1;
	}
#else
	pthread_cond_broadcast(event->cond);
#endif

	return 0;
}
int os_event_destroy(os_event_t *event)
{
	if (!event){
		return 0;
	}
#ifdef WIN32
	if( event->handle ){
		CloseHandle(event->handle);
		event->handle = NULL;
	}
#else
	if (event->cond){
		pthread_cond_destroy(event->cond);
	}
	if (event->mutex){
		pthread_mutex_destroy(event->mutex);
	}
#endif
	free(event);
	event = NULL;

	return 0;
}
